/***************************************************************************
 *   Copyleft 2008-2009 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/

#include "gl/glew.h"
#include <gl/gl.h>
#include <gl/glu.h>		
#include <gl/glut.h>
#include "./vConsole.h"
#include "../../Macros/vLogMacros.h"

namespace Vendetta {
	vChar vConsole::mBuffer [4096];

	vConsole& vConsole::Instance() {
		static vConsole console;

		return console;
	}

	vConsole::~vConsole() {
		mLines.clear();
	}

	vInt vConsole::AddLine(vBool bHeader, const vChar* print, ...) {
		clearBuffer();
		std::stringstream ss;
		va_list args;
		va_start(args, print);
		vsprintf_s(vConsole::mBuffer, print, args);
		va_end(args);

		ss<<vConsole::mBuffer;

		const vConsole::Entry entry(vString(ss.str()), bHeader);

		mLines.push_back(entry);

		return (vInt) mLines.size() - 1;
	}

	vInt vConsole::AddLine(const vString& line, vBool bHeader) {
		const vConsole::Entry entry(line, bHeader);

		mLines.push_back(entry);

		return (vInt) mLines.size() - 1;
	}

	vBool vConsole::EditLine(vInt iIndex, const vChar* print, ...) {
		if (iIndex >= 0 && iIndex < (vInt) mLines.size()) {
			clearBuffer();
			std::stringstream ss;
			va_list args;
			va_start(args, print);
			vsprintf_s(vConsole::mBuffer, print, args);
			va_end(args);

			ss<<vConsole::mBuffer;

			const vConsole::Entry entry(vString(ss.str()), false);

			mLines[iIndex].Msg = ss.str();

			return true;
		}

		return false;
	}

	vBool vConsole::EditLine(vInt iIndex, const vString& line) {
		if (iIndex >= 0 && iIndex < (vInt) mLines.size()) {
			mLines[iIndex].Msg = line;

			return true;
		}

		return false;
	}

	vVoid vConsole::AddBlankLine() {
		mLines.push_back(Entry("<empty/>"));
	}


	vVoid vConsole::PageDown() {
		if (mCurrentPage > 0) {
			mCurrentPage--;
		}
	}

	vVoid vConsole::PageUp() {
		if ((mCurrentPage + 1) < (vInt) mLines.size()) {
			mCurrentPage++;
		}
	}

	vVoid vConsole::SetSize(vInt iWidth, vInt iHeight) {
		mWidth = iWidth;
		mHeight = iHeight;
	}

	vVoid vConsole::Render() {
		prepareToRender();
		glPushMatrix();
		glLoadIdentity();

		glDisable(GL_TEXTURE_2D);
		glDisable(GL_LIGHTING);
		glPopMatrix();

		printPage();
		
		glEnable(GL_LIGHTING);
		glEnable(GL_TEXTURE_2D);
		glMatrixMode(GL_PROJECTION);
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);
	}

	vConsole::vConsole() {
		mMaxLineLength = 200;
		mCurrentPage = 0;
		mMaxLinesPerPage = 60;
	}

	vVoid vConsole::prepareToRender() {
		glMatrixMode(GL_PROJECTION);
		glPushMatrix();
		glLoadIdentity();
		gluOrtho2D(0, mWidth, 0, mHeight);
		glScalef(1, -1, 1);
		glTranslatef(0, -mHeight, 0);
		glMatrixMode(GL_MODELVIEW);
	}

	vVoid vConsole::printPage() {
		if (mCurrentPage >= (vInt) mLines.size()) {
			return;
		}
		for (vInt i = (mCurrentPage * mMaxLinesPerPage); i < ((mCurrentPage + 1) * mMaxLinesPerPage); i++) {
			if (i < (vInt) mLines.size()) {
				printLine(i);
			} else {
				return;
			}
		}
	}

	vVoid vConsole::printLine(vInt iLine) {
		const vChar *c = (mLines[iLine].Msg).ToConstCharPtr();
		vInt x1 = H_SPACING;
		vVoid *font;
		
		if (!strcmp(c, "<empty/>")) {
			return;
		}
		if (mLines[iLine].Type == ENTRY_NORMAL) {
			glColor3f(1.0f, 1.0f, 1.0f);
			font = FONT;
		} else {
			if (iLine == 0) {
				glColor3f(0.0f, 1.0f, 0.0f);
			} else {
				glColor3f(1.0f, 1.0f, 0.0f);
			}
			font = FONT_HEADER;
		}

		for (; *c != '\0'; c++) {
			glRasterPos2f(x1, V_SPACING + iLine * LINE_SPACING);
			glutBitmapCharacter(font, *c);
			x1 = x1 + glutBitmapWidth(font, *c) + CHAR_SPACING;
		}
	}

	vVoid vConsole::clearBuffer() {
		ZeroMemory(vConsole::mBuffer, 4096 * sizeof(vChar));
	}
}
